#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import uuid
import pwd

import psutil

from common.common import execute_cmd, check_command_injection_ex, ParamConstant
from common.const import CMDResult, RpcToolInterface

from generaldb.saphana.comm.saphana_file_operate import log, FileOperate


class CommonFuction:
    def __init__(self):
        pass

    @staticmethod
    def saphana_check_param_safty(param_list:list):
        """
        检查shell命令中，要拼接的参数是否合法
        @@param param_list: 需要进行校验的参数列表
        @@return result:bool 命令执行结果
        """
        for param in param_list:
            if check_command_injection_ex(param):
                return False
        return True

    @staticmethod
    def saphana_check_os_user(id_str):
        """
        检查指定的用户是否存在
        @@param id_str: 指定的用户id
        @@return result:bool 命令执行结果
        """
        try:
            user_info = pwd.getpwnam(f"{id_str}adm")
        except KeyError as ex:
            log.error(f"Current system dose not have user: {id_str}adm")
            return False
        return True

    @staticmethod
    def exec_shell_cmd(cmd_str, system_user="root", need_verify=1):
        """
        切换指定到指定的系统数据用户执行shell命令
        @@param cmd_str: 需要执行的命令
        @@param system_user: 需要su的系统用户，当为root时，表示不需要su
        @@param need_verify: 是否需要对命令内容做防注入校验
        @@return result:bool 命令执行结果
        @@return output:string 命令输出
        """
        if need_verify and check_command_injection_ex(cmd_str):
            return False, "command injection!"
        if check_command_injection_ex(system_user):
            return False, "command injection!"
        if system_user != "root":
            exec_cmd_str = f"su - {system_user} -c '{cmd_str}'"
        else:
            exec_cmd_str = cmd_str
        ret, output, err = execute_cmd(exec_cmd_str)
        if ret == CMDResult.SUCCESS:
            return True, output
        return False, f"err:{err} output:{output}"

    @staticmethod
    def exec_rc_tool_cmd(cmd, in_param, unique_id):
        """
        执行rc_tool命令
        @@param cmd: 需要执行的命令
        @@param in_param: 需要写入输入文件的命令参数
        @@param unique_id: 输入输出文件唯一标识
        @@return result:bool 命令执行结果
        @@return output:string 命令输出
        """
        random_id = str(uuid.uuid4())
        input_file_path = os.path.join(ParamConstant.PARAM_FILE_PATH, \
            ParamConstant.INPUT_FILE_PREFFIX + unique_id + random_id)
        output_file_path = os.path.join(ParamConstant.RESULT_PATH, \
            ParamConstant.OUTPUT_FILE_PREFFIX + unique_id + random_id)
        try:
            FileOperate.write_tmp_file(in_param, input_file_path)
        except Exception as exception_str:
            log.error(f"Write param file exception. {exception_str}")
            if os.path.exists(input_file_path):
                os.remove(input_file_path)
            return False, ""
        cmd = f"{os.path.join(ParamConstant.BIN_PATH, 'rpctool.sh')} {cmd} {input_file_path} {output_file_path}"
        ret, out, err = execute_cmd(cmd)
        if os.path.exists(input_file_path):
            os.remove(input_file_path)
        if ret != CMDResult.SUCCESS:
            log.error(f"An error occur in execute cmd. ret:{ret}. out: {out} err:{err}")
            return False, ""
        output = FileOperate.read_json_file(output_file_path)
        if os.path.exists(output_file_path):
            os.remove(output_file_path)
        if not output:
            log.error(f"Output is null.")
            return False, ""
        return True, output

    @staticmethod
    def report_job_details(job_id: str, sub_job_details: dict):
        log.debug(f"Report details: {sub_job_details}")
        try:
            ret, result_info = CommonFuction.exec_rc_tool_cmd(RpcToolInterface.REPORT_JOB_DETAIL, sub_job_details,
                                                              job_id)
        except Exception as err:
            log.error(f"Invoke rpc_tool interface exception, err: {err}.")
            return False
        if not ret:
            log.error(f"Invoke rpc_tool interface return error, ret: {ret}.")
            return False
        ret_code = result_info.get("code", -1)
        if ret_code != int(CMDResult.SUCCESS):
            log.error(f"Invoke rpc_tool interface failed, result code: {ret_code}.")
            return False
        return True

    @staticmethod
    def filter_pids(filter_name: str, exclude_name: str = None):
        """
        根据指定的名称来筛选出包含filter_name但不是不包含filter_name的进程pid
        """
        log.info(f"Filter name: {filter_name}, exclude name: {exclude_name}.")
        ret_pids = []
        for pid in psutil.pids():
            try:
                process = psutil.Process(pid)
            except Exception as err:
                log.warn(f"Get process err: {err}.")
                continue
            cmd_line = process.cmdline()
            cmd_line_str = ",".join(cmd_line)
            if exclude_name and exclude_name in cmd_line_str:
                continue
            if filter_name in cmd_line_str:
                ret_pids.append(pid)
        log.info(f"Get pids: {ret_pids}.")
        return ret_pids